/*
 * Copyright (c) 2013-2018 上海汇数数据. All rights reserved.
 * @(#) HKChinaID.java 2018-08-05 23:30
 */

package cn.jh.common.core.id;

import cn.jh.common.core.domain.Gender;
import org.inferred.freebuilder.FreeBuilder;
import org.jetbrains.annotations.Contract;

import java.util.regex.Pattern;


/**
 * 中国香港身份证号码信息。
 *
 * @author Fuchun
 * @since 1.0
 */
@FreeBuilder
abstract class HKChinaID extends ChinaID {

    static final String HK_STATE_CODE = "81";
    private static final int HK_ID_LENGTH = 10;
    private static final int HK_ID_LENGTH2 = 11;

    private static final Pattern HK_ID_PATTERN = Pattern.compile("^[A-Z][A-Z]?\\d{6}\\([0-9A]\\)$");

    private static final long serialVersionUID = 2024427812932146922L;

    @Contract(pure = true)
    private static int getCodeValue(char c) {
        if (c < 65 || c > 90) {
            return 0;
        }
        return c - 64;
    }

    private static boolean validIdInner(String id) {
        int sum = 0, numLow = 1, val = 7, vcm;
        char first = id.charAt(0), vc = id.charAt(8), vc2;
        if (id.length() == HK_ID_LENGTH) {
            sum += (getCodeValue(first) * 8);
        } else if (id.length() == HK_ID_LENGTH2) {
            char second = id.charAt(1);
            numLow = 2;
            vc = id.charAt(9);
            sum += (getCodeValue(first) * 9);
            sum += getCodeValue(second) * 8;
        }
        for (char c : id.substring(numLow, numLow + 6).toCharArray()) {
            sum += (c - '0') * val--;
        }
        vcm = sum % 11;
        if (vcm != 0) {
            vcm = 11 - vcm;
        }
        if (vcm == 10) {
            vc2 = 'A';
        } else {
            vc2 = (char) (vcm + 48);
        }
        return vc == vc2;
    }

    @Contract("null -> false")
    public static boolean validId(String id) {
        return !(id == null || id.length() < HK_ID_LENGTH ||
                !HK_ID_PATTERN.matcher(id).matches()) && validIdInner(id);
    }

    public static HKChinaID parse(String id) {
        if (id == null || id.length() < HK_ID_LENGTH ||
                !HK_ID_PATTERN.matcher(id).matches() ||
                !validIdInner(id)) {
            return new Builder(id)
                    .setGender(Gender.UNKNOWN)
                    .setValid(false)
                    .setValidLength(HK_ID_LENGTH).build();
        }
        String areaCode = id.substring(0, 1);
        if (id.length() == HK_ID_LENGTH2) {
            areaCode = id.substring(0, 2);
        }
        return new Builder(id)
                .setAreaCode(areaCode)
                .setGender(Gender.UNKNOWN)
                .setValid(true)
                .setValidLength(id.length())
                .build();
    }

    static class Builder extends HKChinaID_Builder {
        Builder(String id) {
            setNumber(id);
            setAge(-1);
        }
    }

    @Override
    @Contract(pure = true)
    public final String getStateCode() {
        return HK_STATE_CODE;
    }
}
